package com.mic.yzzn.plc.core.control.handler;

import com.mic.yzzn.plc.common.control.datastructure.PLCData;
import com.mic.yzzn.plc.common.control.datastructure.PLCMission;
import com.mic.yzzn.plc.common.control.datastructure.PLCMissionResult;
import com.mic.yzzn.plc.common.ins.datastructure.PLCInstructionTuple;
import com.mic.yzzn.plc.core.control.datastructure.PLCStationConfig;
import com.mic.yzzn.plc.core.control.datastructure.TCPStationConfig;
import com.mic.yzzn.plc.core.internet.TCPInstructionDispatcher;

import java.util.ArrayList;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by ASH on 16/7/18.
 *
 * 用于处理基于 TCP 进行采集的任务的 handler
 */
public class TCPMissionHandler implements PLCMissionHandler {

    private TCPInstructionDispatcher instructionDispatcher;
    private TCPStationConfig stationConfig;

    @Override
    public void setStationConfig(PLCStationConfig stationConfig) {
        this.stationConfig = (TCPStationConfig) stationConfig;
        instructionDispatcher = new TCPInstructionDispatcher(
                ((TCPStationConfig) stationConfig).getPort(),
                ((TCPStationConfig) stationConfig).getHost());
    }

    public long handleCycleMission(PLCMission mission, ConcurrentHashMap<String, PLCData> resultMap, int waitTime) {
        // 发布指令,获取结果,并将结果放入队列中,并计算发送一条指令所需的时间
        long startTime = System.currentTimeMillis();
        ArrayList<PLCInstructionTuple> tuples = instructionDispatcher.sendInstructions(
                mission.getInstructions(),
                false,
                waitTime);
        PLCMissionResult result = new PLCMissionResult(mission.getMissionID());

        long midTime = System.currentTimeMillis();
        System.out.println("读取完毕, 传输耗时: " + (midTime - startTime));

        System.out.println(tuples);

        result.initWithResponseInstruction(tuples);

        // 将结果中的数据取出放入Map中
        for (PLCData data : result.getResultData())
        {
            // 当结果是有意义的值时才更新缓存
            if (data.getState() == 200)
            {
                resultMap.put(data.getDataNumber(), data);
            }
        }

        long endTime = System.currentTimeMillis();
        System.out.println("处理完毕, 处理耗时: " + (endTime - midTime));
        return endTime - startTime;
    }

    @Override
    public void handleReadMission(PLCMission mission, ConcurrentHashMap<UUID, PLCMissionResult> resultMap, int waitTime) {
        int tryTime = 1;

        while (true)
        {
            // 发布指令,获取结果,并将结果放入队列中
            System.out.println("任务首指令: " + mission.getInstructions().get(0));
            ArrayList<PLCInstructionTuple> tuples = instructionDispatcher.sendInstructions(
                    mission.getInstructions(),
                    false,
                    waitTime);
            PLCMissionResult result = new PLCMissionResult(mission.getMissionID());
            result.initWithResponseInstruction(tuples);

            if (mission.getTryToReadTimes() > tryTime && mission.getMissionType() == PLCMission.PLCMissionTypeReadMultiple)
            {
                if (result.isFinished())
                {
                    resultMap.put(result.getResultID(), result);
                    break;
                }
                else
                {
                    System.out.println("第" + tryTime + "次尝试读");
                    ++tryTime;
                }
            }
            else
            {
                resultMap.put(result.getResultID(), result);
                break;
            }
        }
    }

    @Override
    public void handleWriteMission(PLCMission mission, ConcurrentHashMap<UUID, PLCMissionResult> resultMap, int waitTime) {
        // 发布指令,获取结果,并将结果放入队列中
        boolean isAck = (mission.getMissionType() == PLCMission.PLCMissionTypeWriteFireAndAck);
        int tryTime = 1;

        while (true)
        {
            ArrayList<PLCInstructionTuple> tuples = instructionDispatcher.sendInstructions(
                    mission.getInstructions(),
                    isAck,
                    waitTime);
            PLCMissionResult result = new PLCMissionResult(mission.getMissionID());
            result.initWithResponseInstruction(tuples);

            // 检测是否要多次尝试写
            if (mission.getTryToWriteTimes() > tryTime)
            {
                // 检测是否已经完成任务, 否则重新发送
                if (result.isFinished())
                {
                    resultMap.put(result.getResultID(), result);
                    break;
                }
                else
                {
                    System.out.println("第" + tryTime + "次尝试写");
                    ++tryTime;
                }
            }
            else
            {
                resultMap.put(result.getResultID(), result);
                break;
            }
        }

    }
}
